#!/env ruby

#Date,Open,High,Low,Close,Volume,Adj Close
#2013-10-31,11.10,11.10,10.91,10.96,2409400,10.96
#2013-10-30,10.78,11.25,10.67,11.17,4205300,11.17
#2013-10-29,11.30,11.34,10.52,10.82,4836200,10.82

fn = ARGV[0]
if fn==nil
  print "please choose your lucky stock!\n"
end

f = File.open("#{fn}.csv", 'r')
f.readline()    # skip head

h = Hash.new
f.each { |line|
    t = line.chomp.split(/,/)
    if (t[5].to_i==0)   # cut off no volume
      next
    end
    h[t[0]] = [t[2].to_f, t[3].to_f]
}
f.close


################### main class

class Mkat

  attr_accessor :start_date
  attr_accessor :BUY_PT_N_DAYS
  attr_accessor :PD

  attr_accessor :no_msg
  #attr

  def initialize(balance, h)
    ########## compute params #############
    @PD = 2.0
    # start date
    @start_date = "2012-06-01"

    @ENDDATE = "2013-10-31"
    @balance = balance
    @balance_shadow = balance
    @h = h
    @price = avr(@h[@start_date])
    @DATES = @h.keys.sort
    @BUY_PT_N_DAYS = 10
    @no_msg = false
    #########################################
  end

  def avr(l)
    return (l[0] + l[1]) / 2.0
  end

  # function buy_point, decide if it's a buy point for specified date
  def buy_point(d, h)
    if @DATES.index(d)==nil or @DATES.index(d) < @BUY_PT_N_DAYS
      return nil
    end
    p = avr(h[d])
    # currently calc average of 10 days
    s = 0.0
    pre_list = @DATES[(@DATES.index(d) - @BUY_PT_N_DAYS)..@DATES.index(d)]
    pre_list.each { |e|
      s += avr(h[e])
    }
    if p < (s / pre_list.length)
      return true
    else
      return false
    end
  end

  def sell_point(d, h, p)
    if 100 * (h[d][0] - p) / p > @PD
      return true
    else
      return false
    end
  end


  def simulate()
    # init simulate here
    state = :sell
    @price = avr(@h[@start_date])
    @balance = @balance_shadow

    @h.keys.sort.each { |d|
      if d <= @start_date
        next
      end
      if d >= @ENDDATE
        break
      end
      if state==:sell
        if sell_point(d, @h, @price)==true
          # sell
          # should be predictable here
          @balance = @balance * (1 + @PD / 100.0)
          #if @no_msg
            print "Selling at price #{@price * (1 + @PD)} date: #{d}: balance is #{@balance}.\n"
          #end
          @start_date = d
          state = :buy
        else
          if @no_msg
            print "Waiting for Sell Pt.\n"
          end
        end
      else
        if buy_point(d, @h)==nil
          exit "sth rong."
        elsif buy_point(d, @h)==true
          state = :sell
          @price = avr(@h[d])
          #if @no_msg
            print "Buying #{d}: price is #{@price}.\n"
          #end
        else
          if @no_msg
            print "Waiting for Buy Pt.\n"
          end
        end
      end
    }

    print "state: #{state}, held price is #{@price}, balance is #{@balance}.\n"

  end   # end simulate

end # end class

m = Mkat.new(10000, h)

m.start_date = "2012-05-24"
#m.no_msg = true


###### simulate here ############
pd = 10
days = 60

days.downto(1) { |d|
  pd.downto(1) { |p|
    print "-------- PD = #{p}, Days = #{d} -------\n"
    m.BUY_PT_N_DAYS = d
    m.PD = p.to_f
    m.simulate
  }
  print "\n\n"
}
